#include "stdafx.h"
#include "strhelper.h"
#include <stdarg.h>
#include <boost/locale.hpp>
#include <list>

std::string str_format(const char *pszFmt, ...)
{
    std::string str;
    va_list args;
    va_start(args, pszFmt);
    {
        int nLength = _vscprintf(pszFmt, args);
        str.resize(nLength);
        _vsnprintf(const_cast<char*>(str.data()), nLength, pszFmt, args);
    }
    va_end(args);
    return str;
}
std::wstring str_format(const wchar_t*pszFmt,...)
{
    std::wstring str;
    va_list args;
    va_start(args, pszFmt);
    {
        int nLength = _vscwprintf(pszFmt, args);
        str.resize(nLength);
        _vsnwprintf(const_cast<wchar_t*>(str.data()), nLength, pszFmt, args);
    }
    va_end(args);
    return str;
}
/*

function str_encode_to_jscode(str)
{
    str=new String(str);
    return str.replace(/([\n\r\"\'\t\\\b\f\0])/g,function(pd){
        switch(pd)
        {
            case '\n': return '\\n';
            case '\r': return '\\r';
            case '\"': return '\\"';
            case '\'': return '\\\'';
            case '\t': return '\\t';
            case '\\': return '\\\\';
            case '\b': return '\\b';
            case '\f': return '\\f';
            case '\0': return '\\0';
        }
    });
}


*/

std::wstring str_encode_to_jscode(const std::wstring& str)
{
    size_t sp=str.size();
    size_t strn=sp;
    const wchar_t * pstr=str.data();
    for(size_t i=0;i<strn;++i)
    {
        switch (pstr[i]) {
        case L'\n':
        case L'\r':
        case L'\'':
        case L'"':
        case L'\t':
        case L'\\':
        case L'\b':
        case L'\f':
        case L'\0':
            ++sp;
            break;
        }
    }
    if(sp==str.size())
        return str;

    std::wstring rstr;
    rstr.reserve(sp);
    sp=0;
    for(size_t i=0;i<strn;++i)
    {
        switch (pstr[i]) {
        case L'\n':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\n",2);
            sp=i+1;
            break;
        case L'\r':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\r",2);
            sp=i+1;
            break;
        case L'\'':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\'",2);
            sp=i+1;
            break;
        case L'"':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\\"",2);
            sp=i+1;
            break;
        case L'\t':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\t",2);
            sp=i+1;
            break;
        case L'\\':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\\\",2);
            sp=i+1;
            break;
        case L'\b':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\b",2);
            sp=i+1;
            break;
        case L'\f':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\f",2);
            sp=i+1;
            break;
        case L'\0':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append(L"\\0",2);
            sp=i+1;
            break;
        }
    }
    if(sp<strn)
    {
        rstr.append(pstr+sp,pstr+strn);
    }
    return rstr;
}

std::string str_encode_to_jscode(const std::string& str)
{
    size_t sp=str.size();
    size_t strn=sp;
    const char * pstr=str.data();
    for(size_t i=0;i<strn;++i)
    {
        switch (pstr[i]) {
        case '\n':
        case '\r':
        case '\'':
        case '"':
        case '\t':
        case '\\':
        case '\b':
        case '\f':
        case '\0':
            ++sp;
            break;
        }
    }
    if(sp==str.size())
        return str;

    std::string rstr;
    rstr.reserve(sp);
    sp=0;
    for(size_t i=0;i<strn;++i)
    {
        switch (pstr[i]) {
        case '\n':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\n",2);
            sp=i+1;
            break;
        case '\r':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\r",2);
            sp=i+1;
            break;
        case '\'':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\'",2);
            sp=i+1;
            break;
        case '"':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\\"",2);
            sp=i+1;
            break;
        case '\t':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\t",2);
            sp=i+1;
            break;
        case '\\':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\\\",2);
            sp=i+1;
            break;
        case '\b':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\b",2);
            sp=i+1;
            break;
        case '\f':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\f",2);
            sp=i+1;
            break;
        case '\0':
            if(sp<i){rstr.append(pstr+sp,pstr+i);}
            rstr.append("\\0",2);
            sp=i+1;
            break;
        }
    }
    if(sp<strn)
    {
        rstr.append(pstr+sp,pstr+strn);
    }
    return rstr;
}



std::wstring regex_replace(const std::wstring & str, const std::wregex & rgx,
    std::function<std::wstring(std::wsmatch&)> fun)
{
    std::wsmatch sm;
    std::wostringstream oss(std::ios::binary);
    std::wstring::const_iterator bg, ed;
    bg = str.cbegin();
    ed = str.cend();
    for (;;)
    {
        if (std::regex_search(bg, ed, sm, rgx))
        {

            if (bg != sm[0].first)
            {
                oss << std::wstring(bg, sm[0].first);
            }
            oss << fun(sm);
            bg = sm[0].second;
        }
        else
        {
            oss << std::wstring(bg, ed);
            break;
        }
    }
    return oss.str();
}

std::string regex_replace(const std::string & str, const std::regex & rgx,
    std::function<std::string(std::smatch&)> fun)
{
    std::smatch sm;
    std::ostringstream oss(std::ios::binary);
    std::string::const_iterator bg, ed;
    bg = str.cbegin();
    ed = str.cend();
    for (;;)
    {
        if (std::regex_search(bg, ed, sm, rgx))
        {

            if (bg != sm[0].first)
            {
                oss << std::string(bg, sm[0].first);
            }
            oss << fun(sm);
            bg = sm[0].second;
        }
        else
        {
            oss << std::string(bg, ed);
            break;
        }
    }
    return oss.str();
}
static const char sg_trim_chars[]=" \r\n\t";
static const wchar_t sg_trim_wchars[]=L" \r\n\t";
std::string str_ltrim(const std::string &str, const char *trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_chars;
    }
    const char* head=str.data();
    const char* beg=head;
    const char* ed=head+str.size();
    while(beg<ed)
    {
        if(str_chr(trim_chars,*beg)>=0)
        {
            ++beg;
        }else {
            break;
        }
    }
    return head==beg?str:std::string(beg,ed);
}

std::string str_rtrim(const std::string &str, const char *trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_chars;
    }

    const char* beg=str.data();
    const char* ed=beg+str.size();
    const char* tail=ed;

    while(beg<ed)
    {
        if(str_chr(trim_chars,ed[-1])>=0)
        {
            --ed;
        }else {
            break;
        }
    }
    return tail==ed?str:std::string(beg,ed);
}

std::string str_trim(const std::string &str, const char *trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_chars;
    }
    const char* head=str.data();
    const char* beg=head;
    const char* ed=head+str.size();
    const char* tail=ed;

    while(beg<ed)
    {
        if(str_chr(trim_chars,*beg)>=0)
        {
            ++beg;
        }else {
            do{
                if(str_chr(trim_chars,ed[-1])>=0)
                {
                    --ed;
                }else {
                    break;
                }
            }while(beg<ed);
            break;
        }
    }
    return (head==beg)&&(tail==ed)?str:std::string(beg,ed);
}

std::wstring str_ltrim(const std::wstring & str,const wchar_t* trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_wchars;
    }
    const wchar_t* head=str.data();
    const wchar_t* beg=head;
    const wchar_t* ed=head+str.size();
    while(beg<ed)
    {
        if(str_chr(trim_chars,*beg)>=0)
        {
            ++beg;
        }else {
            break;
        }
    }
    return head==beg?str:std::wstring(beg,ed);
}
std::wstring str_rtrim(const std::wstring & str,const wchar_t* trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_wchars;
    }

    const wchar_t* beg=str.data();
    const wchar_t* ed=beg+str.size();
    const wchar_t* tail=ed;

    while(beg<ed)
    {
        if(str_chr(trim_chars,ed[-1])>=0)
        {
            --ed;
        }else {
            break;
        }
    }
    return tail==ed?str:std::wstring(beg,ed);
}
std::wstring str_trim(const std::wstring & str,const wchar_t* trim_chars)
{
    if(trim_chars==NULL)
    {
        trim_chars=sg_trim_wchars;
    }
    const wchar_t* head=str.data();
    const wchar_t* beg=head;
    const wchar_t* ed=head+str.size();
    const wchar_t* tail=ed;

    while(beg<ed)
    {
        if(str_chr(trim_chars,*beg)>=0)
        {
            ++beg;
        }else {
            do{
                if(str_chr(trim_chars,ed[-1])>=0)
                {
                    --ed;
                }else {
                    break;
                }
            }while(beg<ed);
            break;
        }
    }
    return (head==beg)&&(tail==ed)?str:std::wstring(beg,ed);
}

std::string utf2s(const std::string & str)
{
    return boost::locale::conv::between(str,"GBK","UTF-8");
}
std::string s2utf(const std::string & str)
{
    return boost::locale::conv::between(str,"UTF-8","GBK");
}

std::wstring s2ws(const std::string & str)
{
    return boost::locale::conv::to_utf<wchar_t>(str,"GBK");
}
std::string  ws2s(const std::wstring & str)
{
    return boost::locale::conv::from_utf(str,"GBK");
}

std::string ws2utf(const std::wstring & str)
{
    return boost::locale::conv::utf_to_utf<char,wchar_t>(str);
}
std::wstring utf2ws(const std::string & str)
{
    return boost::locale::conv::utf_to_utf<wchar_t,char>(str);
}



std::string str_erase(const std::string & str,const std::string & fndstr,size_t pos,size_t repcount)
{
    if(pos>=str.size())
        return str;
    if(fndstr.empty())
        return str;
    struct fnd_info
    {
        const char* str;
        size_t      len;
    };
    size_t nsz=0;
    size_t npos;
    size_t tsz;
    std::list<fnd_info> fnds;
    if(pos>0)
    {
        fnds.push_back({str.data(),pos});
    }
    for(;repcount>0;--repcount)
    {
        npos=str.find(fndstr,pos);
        if(npos!=str.npos)
        {
            tsz=npos-pos;
            if(tsz)
            {
                fnds.push_back({str.data()+pos,tsz});
                nsz+=tsz;
            }
            pos=npos+fndstr.size();
        }else {
            break;
        }
    }
    tsz=str.size()-pos;
    if(tsz)
    {
        nsz+=tsz;
        fnds.push_back({str.data()+pos,tsz});
    }
    std::string retstr;
    retstr.reserve(nsz);
    for(auto & ts : fnds)
    {
        retstr.append(ts.str,ts.len);
    }
    return retstr;
}



std::string str_replace(const std::string & str,const std::string & fndstr,const std::string & repstr,size_t pos,size_t repcount)
{
    if(pos>=str.size())
        return str;
    if(repstr.empty())
    {
        return str_erase(str,fndstr,pos,repcount);
    }
    if(fndstr.empty())
        return str;
    struct fnd_info
    {
        const char* str;
        size_t      len;
    };
    size_t nsz=0;
    size_t npos;
    size_t tsz;
    std::list<fnd_info> fnds;
    if(pos>0)
    {
        fnds.push_back({str.data(),pos});
    }
    for(;repcount>0;--repcount)
    {
        npos=str.find(fndstr,pos);
        if(npos!=str.npos)
        {
            tsz=npos-pos;
            if(tsz)
            {
                fnds.push_back({str.data()+pos,tsz});
                nsz+=tsz;
            }
            fnds.push_back({repstr.data(),repstr.size()});
            nsz+=repstr.size();
            pos=npos+fndstr.size();
        }else {
            break;
        }
    }
    tsz=str.size()-pos;
    if(tsz)
    {
        nsz+=tsz;
        fnds.push_back({str.data()+pos,tsz});
    }
    std::string retstr;
    retstr.reserve(nsz);
    for(auto & ts : fnds)
    {
        retstr.append(ts.str,ts.len);
    }
    return retstr;
}
std::wstring str_erase(const std::wstring & str,const std::wstring & fndstr,size_t pos,size_t repcount)
{
    if(pos>=str.size())
        return str;
    if(fndstr.empty())
        return str;
    struct fnd_info
    {
        const wchar_t* str;
        size_t      len;
    };
    size_t nsz=0;
    size_t npos;
    size_t tsz;
    std::list<fnd_info> fnds;
    if(pos>0)
    {
        fnds.push_back({str.data(),pos});
    }
    for(;repcount>0;--repcount)
    {
        npos=str.find(fndstr,pos);
        if(npos!=str.npos)
        {
            tsz=npos-pos;
            if(tsz)
            {
                fnds.push_back({str.data()+pos,tsz});
                nsz+=tsz;
            }
            pos=npos+fndstr.size();
        }else {
            break;
        }
    }
    tsz=str.size()-pos;
    if(tsz)
    {
        nsz+=tsz;
        fnds.push_back({str.data()+pos,tsz});
    }
    std::wstring retstr;
    retstr.reserve(nsz);
    for(auto & ts : fnds)
    {
        retstr.append(ts.str,ts.len);
    }
    return retstr;
}

std::wstring str_replace(const std::wstring & str,const std::wstring & fndstr,const std::wstring & repstr,size_t pos,size_t repcount)
{
    if(pos>=str.size())
        return str;
    if(repstr.empty())
    {
        return str_erase(str,fndstr,pos,repcount);
    }
    if(fndstr.empty())
        return str;
    struct fnd_info
    {
        const wchar_t* str;
        size_t      len;
    };
    size_t nsz=0;
    size_t npos;
    size_t tsz;
    std::list<fnd_info> fnds;
    if(pos>0)
    {
        fnds.push_back({str.data(),pos});
    }
    for(;repcount>0;--repcount)
    {
        npos=str.find(fndstr,pos);
        if(npos!=str.npos)
        {
            tsz=npos-pos;
            if(tsz)
            {
                fnds.push_back({str.data()+pos,tsz});
                nsz+=tsz;
            }
            fnds.push_back({repstr.data(),repstr.size()});
            nsz+=repstr.size();
            pos=npos+fndstr.size();
        }else {
            break;
        }
    }
    tsz=str.size()-pos;
    if(tsz)
    {
        nsz+=tsz;
        fnds.push_back({str.data()+pos,tsz});
    }
    std::wstring retstr;
    retstr.reserve(nsz);
    for(auto & ts : fnds)
    {
        retstr.append(ts.str,ts.len);
    }
    return retstr;
}

